package utils

import (
	"errors"
	"fmt"
	"time"
)

const (
	// 获取当前时间字符串的固定格式
	CurrentTimeFormat = "2006-01-02 15:04:05"

	MYNano      = "2006-01-02 15:04:05.000000000"
	MYMicro     = "2006-01-02 15:04:05.000000"
	MYMil       = "2006-01-02 15:04:05.000"
	MYSec       = "2006-01-02 15:04:05"
	MYCST       = "2006-01-02 15:04:05 +0800 CST"
	MYUTC       = "2006-01-02 15:04:05 +0000 UTC"
	MYDate      = "2006-01-02"
	MYTime      = "15:04:05"
	FBTIME      = "2006-01-02T15:04:05+0800"
	APPTIME     = "2006-01-02T15:04:05.000"
	TWITTERTIME = "2006-01-02T15:04:05Z"
)

var TimeLocation *time.Location

func init() {
	var err error
	TimeLocation, err = time.LoadLocation("Asia/Shanghai")
	if err != nil {
		panic(err)
	}
}

// 使用缓存重构的活动时间节点
func GetCacheActivityStartTime() time.Time {
	return time.Date(2023, 12, 12, 0, 0, 0, 0, TimeLocation)
}

func GetCurrentTime() time.Time {
	return time.Now().In(TimeLocation)
}

func GetCurrentTimeString() string {
	return time.Now().In(TimeLocation).Format(CurrentTimeFormat)
}

// 时间转时间戳(秒)
func Time2TimeStampSecond(t time.Time) int64 {
	return t.Unix()
}

// 时间转时间戳(毫秒)
func Time2TimeStampMilliSecond(t time.Time) int64 {
	return t.UnixMilli()
}

// 当前毫秒级别时间戳
func GetCurrentTimeStampMilli() int64 {
	return time.Now().In(TimeLocation).UnixMilli()
}

// 当前秒级别时间戳
func GetCurrentTimeStampSec() int64 {
	return time.Now().In(TimeLocation).Unix()
}

// 间戳转时间系列
// 第一个参数表示秒级别的时间戳，第二个参数表示纳秒级别的时间戳，如果是毫秒级别的时间戳需要先乘以1e6然后放入第二个参数即可
func timestamp2Time(sec int64, nsec int64) time.Time {
	return time.Unix(sec, nsec).In(TimeLocation)
}

// 秒级别时间戳转时间
func TimestampSec2Time(sec int64) time.Time {
	return timestamp2Time(sec, 0).In(TimeLocation)
}

// 毫秒级别时间戳转时间
func TimestampMilli2Time(stamp int64) time.Time {
	return timestamp2Time(0, stamp*1e6).In(TimeLocation)
}

// 纳秒级别时间戳转时间
func TimestampNano2Time(stamp int64) time.Time {
	return timestamp2Time(0, stamp).In(TimeLocation)
}

// 返回参数1: t1时间减去t2时间的时间差
// 返回参数2: t1时间是否在t2时间的后面
func GetTimeSubSecs(t1, t2 time.Time) time.Duration {
	// Notice 后面不要加Seconds()方法，有时候即使t1在t2后面返回的也有可能是一个负数!
	return t1.Sub(t2)
}

// 时间字符串转时间
func TimeStr2Time(timeStr string) (time.Time, error) {
	// 可能的转换格式
	useFormat := []string{
		MYNano, MYMicro, MYMil, MYSec, MYCST, MYUTC, MYDate, MYTime, FBTIME, APPTIME, TWITTERTIME,
		time.RFC3339,
		time.RFC3339Nano,
	}
	var t time.Time // 默认: 0001-01-01 00:00:00 +0000 UTC
	for _, useF := range useFormat {
		tt, err1 := time.ParseInLocation(useF, timeStr, TimeLocation)
		if err1 != nil {
			continue
		}
		t = tt
		break
	}
	if t == getTimeDefault() { // 0001-01-01 00:00:00 +0000 UTC
		return t, errors.New(fmt.Sprintf("时间字符串格式错误! timeStr: %v", timeStr))
	}
	return t, nil
}

func getTimeDefault() time.Time {
	t, _ := time.ParseInLocation("2006-01-02 15:04:05", "", TimeLocation)
	return t
}

// 当前时间加7天时间的秒级时间戳
func GetAfter7DaysTimestampSec() int64 {
	t7 := GetCurrentTime().Add(time.Hour * 24 * 7)
	return Time2TimeStampSecond(t7)
}
